-------------------------------------------------------------------------------------
-- -*- coding: utf-8 -*-
--
-- @author:   zxf
-- @email:    07291@qq.com
-- @date:     2024/5/28
-- @module:   main_target
-- @describe:
-- @version:  v1.0
--

-------------------------------------------------------------------------------------

---@class main_target
local main_target = {}
local this = main_target
local trace = trace
local import = import
---@type MAIN_TARGET_TYPE_CONFIG
local MAIN_TARGET_TYPE_CONFIG = import('bt/custom_node/enum_type_cfg/MAIN_TARGET_TYPE_CONFIG')
local PRIORITY_CONFIG = MAIN_TARGET_TYPE_CONFIG.PRIORITY_CONFIG
local CUSTOM_PRIORITY_CONFIG = MAIN_TARGET_TYPE_CONFIG.CUSTOM_PRIORITY_CONFIG
local MAIN_TARGET_TYPE = MAIN_TARGET_TYPE_CONFIG.TYPE

-- 设置优先级配置
function this.set_priority_config(cfg)
    PRIORITY_CONFIG = cfg
end

--- 得到指定目标优先级配置
--- @param mainTargetName string 目标名字
function this.get_main_target_priority_config(mainTargetName)
    return PRIORITY_CONFIG[mainTargetName]
end

--- 得到自定义优先级配置
--- @param mainTargetName string 目标名字
function this.get_custom_main_target_priority_config(mainTargetName)
    if CUSTOM_PRIORITY_CONFIG and CUSTOM_PRIORITY_CONFIG[mainTargetName] then
        return CUSTOM_PRIORITY_CONFIG[mainTargetName]
    end
    return nil
end

--- 目标优先级比较
--- @param curMainTargetName string 当前目标名字
--- @param compareMainTargetName string 比较的目标名字
function this.compare_main_target_priority(curMainTargetName, compareMainTargetName)
    local curCfg = this.get_main_target_priority_config(curMainTargetName)
    if not curCfg then
        trace.log_trace(string.format('查找目标【%s】配置失败', curMainTargetName))
        return true
    end
    local compareCfg = nil
    local customCfg = this.get_custom_main_target_priority_config(curMainTargetName)
    if customCfg and customCfg[compareMainTargetName] then
        compareCfg = customCfg[compareMainTargetName]
    else
        compareCfg = this.get_main_target_priority_config(compareMainTargetName)
        if not compareCfg then
            trace.log_trace(string.format('查找目标【%s】配置失败', compareMainTargetName))
            return true
        end
    end
    return curCfg.priority <= compareCfg.priority
end

--- 检查当前目标是否能打断
--- @param owner owner_base 自身数据
--- @param targetName string 对比的目标名字
--- @param notCheckPriority boolean 不检查优先级
function this.check_break_main_target(owner, targetName, notCheckPriority)
    if owner:check_curMainTarget(targetName) then
        return false
    end
    if not owner:check_curMainTarget(MAIN_TARGET_TYPE.NONE) then
        -- 优先级判断
        if not notCheckPriority then
            if this.compare_main_target_priority(owner:get_curMainTarget(), targetName) then
                trace.log_trace(string.format('设置主要目标【%s】失败 当前目标为【%s】', targetName, owner:get_curMainTarget()))
                return false
            end
        end
    end
    return true
end

--- 打断目标
--- @param owner owner_base 自身数据
--- @param targetName string 打断的目标
--- @param notCheckPriority boolean 不检查优先级
--- @param mainTargetData any 当前目标附带的数据
function this.break_main_target(owner, targetName, notCheckPriority, mainTargetData)
    return owner:break_main_target(targetName, notCheckPriority, mainTargetData)
end

--- 设置主目标
--- @param owner owner_base 自身数据
--- @param targetName string 目标名字
function this.set_main_target(owner, targetName)
    local cfg = this.get_main_target_priority_config(targetName)
    if not cfg then
        trace.log_trace('设置主要目标失败请查看配置')
        trace.log_trace(targetName)
        return false
    end
    owner:set_curMainTarget(targetName)
    local logStr = string.format('设置主要目标【%s】', cfg.name)
    trace.log_trace(logStr)
    if main_ctx then
        main_ctx:set_action(logStr)
    end
    return true
end

--- 完成目标时处理
--- @param owner owner_base 自身数据
function this.on_complete_main_target(owner)
    local targetName = owner:get_curMainTarget()
    -- 完成记录
    owner:set_curMainTarget(MAIN_TARGET_TYPE.NONE)
    -- 移除完成的目标
    if owner:is_there_mainTarget_in_mainTargetArr() then
        local curCfg = owner:get_mainTargetData_from_mainTargetArr(1)
        if curCfg.mainTarget == targetName then
            owner:remove_mainTarget_from_mainTargetArr(1)
        end
    end
    -- 完成后插入判断
    local curMainTargetCompleteState = owner:get_cur_main_target_complete_state()
    if curMainTargetCompleteState then
        if curMainTargetCompleteState.mainTarget == targetName then
            local isFail = curMainTargetCompleteState.isFail
            local mainTargetCompleteData = owner:get_complete_mainTarget_from_dic(targetName)
            if mainTargetCompleteData then
                local insertIndex = 1
                for _, v in ipairs(mainTargetCompleteData) do
                    local insertCond = v.insertCond
                    if (insertCond == 1 and not isFail) or (insertCond == 2 and isFail) or insertCond == 3 then
                        local logStr = isFail and '失败' or '成功'
                        this.remove_main_target(owner, v.data.mainTarget)
                        trace.log_trace(string.format('目标:【%s】执行结果:【%s】需插入:【%s】', targetName, logStr, v.data.mainTarget))
                        this.insert_main_target(owner, v.data.mainTarget, v.data.data, true, true, insertIndex)
                        insertIndex = insertIndex + 1
                    end
                end
                -- 清理插入完的数据
                owner:clear_complete_mainTarget_from_dic_by_name(targetName)
            end
        else
            trace.log_trace(string.format('目标【%s】完成状态数据不匹配', targetName))
        end
    else
        trace.log_trace(string.format('目标【%s】 没有完成状态的数据', targetName))
    end

    -- 推进下一个目标
    if owner:is_there_mainTarget_in_mainTargetArr() then
        local tmpData = owner:get_mainTargetData_from_mainTargetArr(1)
        if not this.set_main_target(owner, tmpData.mainTarget, tmpData.notCheckPriority) then
            owner:remove_mainTarget_from_mainTargetArr(1)
        else
            trace.log_trace(string.format('推进到下一个目标【%s】成功', tmpData.mainTarget))
        end
    end
end

--- 插入目标到目标列表
--- @param owner owner_base 自身数据
--- @param mainTargetName string 目标名字
--- @param mainTargetData any 目标数据
--- @param notCheckRepeat boolean 不检查重复
--- @param notCheckPriority boolean 不检查优先级
--- @param insertIndex number 插入位置
--- @param isRemoveMainTarget boolean 插入成功是否移除所有该目标
function this.insert_main_target(owner, mainTargetName, mainTargetData, notCheckRepeat, notCheckPriority, insertIndex, isRemoveMainTarget)
    local mainTargetArrCount = owner:get_mainTargetArrCount()
    if not notCheckRepeat then
        for i = 1, mainTargetArrCount do
            local compareMainTarget = mainTargetName
            if owner:check_mainTargetType_from_mainTargetArr(i, compareMainTarget) then
                trace.log_trace(string.format("有重复目标【%s】在列表中", compareMainTarget))
                return
            end
        end
    end
    local resIndex = insertIndex
    if resIndex then
        local isInsertIndex = false
        if not notCheckPriority then
            for i = resIndex, mainTargetArrCount do
                local tmpMainTarget = owner:get_mainTargetData_from_mainTargetArr(i).mainTarget
                local compareMainTarget = mainTargetName
                if not this.compare_main_target_priority(tmpMainTarget, compareMainTarget) then
                    isInsertIndex = true
                    resIndex = i
                    break
                end
            end
        else
            isInsertIndex = true
        end
        -- 没有合适的位置就插入到最后
        if not isInsertIndex then
            resIndex = mainTargetArrCount + 1
        end
    else
        resIndex = mainTargetArrCount + 1
    end
    if isRemoveMainTarget then
        this.remove_all_main_target_by_name(owner, mainTargetName)
    end
    trace.log_trace(string.format("目标【%s】插入到列表【%s】中", mainTargetName, resIndex))
    owner:insert_mainTarget_in_mainTargetArr(resIndex, { mainTarget = mainTargetName, data = mainTargetData })
end

--- 移除指定的所有目标
function this.remove_all_main_target_by_name(owner, mainTargetName)
    while(this.remove_main_target(owner, mainTargetName)) do end
end

--- 移除目标
--- @param owner owner_base 自身数据
--- @param mainTargetName string 目标名字
function this.remove_main_target(owner, mainTargetName)
    local mainTargetArrCount = owner:get_mainTargetArrCount()
    for i = 1, mainTargetArrCount do
        if owner:check_mainTargetType_from_mainTargetArr(i, mainTargetName) then
            owner:remove_mainTarget_from_mainTargetArr(i)
            trace.log_trace(string.format("目标【%s】从列表位置【%s】移除", mainTargetName, i))
            return true
        end
    end
    return false
end

--- 得到目标列表中的数据
--- @param owner owner_base 自身数据
--- @param checkIndex number 列表索引
--- @param mainTargetName string 目标名字（不填就按索引位置查到）
function this.get_main_target_arr_data_by_index(owner, checkIndex, mainTargetName)
    local mainTargetData = owner:get_mainTargetData_from_mainTargetArr(checkIndex)
    if not mainTargetData then
        return nil
    end
    if mainTargetName then
        if owner:check_mainTargetType_from_mainTargetArr(checkIndex, mainTargetName) then
            return mainTargetData.data
        end
    else
        return mainTargetData.data
    end
end

return this